package com.hd123.rumba.gwt.widget.client;

import java.util.List;

import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.rpc.AsyncCallback;

/**
 * 多个异步动作序列，串行的执行
 * 
 * @author LiQi
 *
 */
public class BatchAsyncAction {

  private int actionCount = 0;
  private List objects;
  private Callback callback;
  private int currentIndex = 0, successCount = 0, failureCount = 0;
  protected AsyncCallback singleCallback = new SingleCallback();

  /**
   * @param actionCount 动作的数量
   * @param objects 动作序列中每个动作对应的对象，可以传入任意对象，会被传给callback.execute，可以为空
   * @param callback
   */
  public BatchAsyncAction(int actionCount, List objects, Callback callback) {
    this.actionCount = actionCount;
    this.objects = objects;
    this.callback = callback;
  }

  public void start() {
    currentIndex = -1;
    next();
  }

  private void next() {
    currentIndex++;
    if (currentIndex < actionCount) {
      Object object = objects == null ? null : objects.get(currentIndex);
      String progress = NumberFormat.getFormat("0")
        .format((currentIndex + 1) * 1.0 / actionCount * 100)
        + "%";
      callback.execute(currentIndex, object, progress, singleCallback);
    } else {
      callback.onFinish(successCount == actionCount, successCount, failureCount);
    }
  }

  private class SingleCallback implements AsyncCallback {

    public void onFailure(Throwable caught) {
      failureCount++;
      if (callback.onFailure(currentIndex, caught))
        next();
    }

    public void onSuccess(Object result) {
      successCount++;
      callback.onSuccess(currentIndex, result);
      next();
    }

  }

  /**
   * BatchAsyncAction的事件接口
   * 
   * @author LiQi
   *
   */
  public interface Callback {

    /**
     * 执行动作序列中的一个动作
     * 
     * @param currentIndex 当前动作的序号
     * @param object 当前动作对应的对象
     * @param callback 实现者应把callback传给自己的异步调用接口
     */
    void execute(int index, Object object, String progress, AsyncCallback callback);

    /**
     * 单个动作失败
     * 
     * @param index 当前动作的序号
     * @param caught
     * @return 是否继续执行下一个动作
     */
    boolean onFailure(int index, Throwable caught);

    /**
     * 单个动作成功
     * 
     * @param index 当前动作的序号
     * @param result
     */
    void onSuccess(int index, Object result);

    /**
     * 所有动作都成功后执行的动作
     * 
     */
    void onFinish(boolean allSuccess, int successCount, int failureCount);

  }
}
